/* Miscellaneous Utility Functions */

//  Text Parsing                                                          >fold>
#include <ctype.h>
#include <strings.h>

#include "utility.h"

char *skip_spaces (char *p)
    {
    if ( p )
        while( *p && isspace(*p) )
            p++;
    return p;
    }

char *trim_spaces (char *p)
    {
    if ( !p ) return 0;
    p = skip_spaces(p);
    char *start = p;
    while ( *p ) p++;  // continue on to the end of the string
    // back up while the previous char is a space
    while ( start < (p-1) && isspace(*(p-1)) ) p--;
    if ( *p ) *p = '\0';  // now trim the end spacing
    return start;
    }

// returns the char after the next token (optionally skipping spaces first)
// sets the token (if found) to '\0'
char *next_token (char *p, char token, bool skip_spaces)
    {
    if ( !p ) return 0;
    while ( *p && *p != token ) p++;
    if ( *p == '\0' ) return 0;
    *p = '\0'; p++;
    if ( skip_spaces )
        while ( isspace(*p) ) p++;
    return ( *p == '\0' ) ? 0 : p;
    }

bool is_false_string (const char *str)
    {
    return ( strcasecmp(str, "false") == 0 || strcasecmp(str, "0") == 0 ||
             strcasecmp(str, "no") == 0 || strcasecmp(str, "disable") == 0 ||
             strcasecmp(str, "disabled") == 0 || strcasecmp(str, "off") == 0 );
    }

bool is_true_string (const char *str)
    {
    return ( strcasecmp(str, "true") == 0 || strcasecmp(str, "1") == 0 ||
             strcasecmp(str, "yes") == 0 || strcasecmp(str, "enable") == 0 ||
             strcasecmp(str, "enabled") == 0 || strcasecmp(str, "on") == 0 );
    }

//
// ---------------------------------------------------------------------- <fold<
//  Simplistic Associative Array                                          >fold>

// (index and/or value may be 0)
bool assoc_match (const char *str, struct assoc_array array[],
                  int *return_index, int *return_value)
    {
    for ( int i = 0; array[i].key; i++ )
        if ( strcasecmp(array[i].key, str) == 0 )
            {
            if ( return_index )
                *return_index = i;
            if ( return_value )
                *return_value = array[i].value;
            return true;
            }
    return false;
    }
//
// Caution: This merely matches the first element that has the same value;
//          this may not be useful unless the array has unique values.
// (index and/or key may be 0)
bool assoc_by_value (int value, struct assoc_array array[],
                     int *return_index, const char **return_key)
    {
    for ( int i = 0; array[i].key; i++ )
        if ( array[i].value == value )
            {
            if ( return_index )
                *return_index = i;
            if ( return_key )
                *return_key = array[i].key;
            return true;
            }
    return false;
    }

// ---------------------------------------------------------------------- <fold<

// takes the mid point between point1 and point2, then moves point1/point2
// distance/2 in opposite directions.
// returns the distance used.
double center_points (double *point1, double *point2, double distance,
                      double max_distance)
    {
    double middle = (*point1 + *point2) / 2;
    if ( max_distance > 0 && distance > max_distance )
        distance = max_distance;
    *point1 = middle - distance/2;
    *point2 = middle + distance/2;
    return distance;
    }
